package com.example.day3.stream;

import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

public class C13GroupingByTest {
    record Hero(String name, int strength) {

    }

    public static void main(String[] args) {
        // 注意下述的代码都使用了静态导入的写法不用写Collectors.了
        Stream<Hero> stream = Stream.of(
                new Hero("令狐冲", 90),
                new Hero("风清扬", 98),
                new Hero("独孤求败", 100),
                new Hero("方证", 92),
                new Hero("东方不败", 98),
                new Hero("冲虚", 90),
                new Hero("向问天", 88),
                new Hero("任我行", 92),
                new Hero("不戒", 88)
        );

        /*
         1. mapping(x->y, dc)  需求:根据名字长度分组,分组后组内只保留他们的武力值
            第一个参数用于先将流中的数据做一个转换 new Hero("令狐冲", 90) -> 90
            dc是 下游收集器 down collector 用于指定把转换后的结果收集到哪里去
         */
        // Map<Integer, List<Integer>> collect = stream.collect(groupingBy(h -> h.name().length(), mapping(s -> s.strength(), toList())));
        // 使用方法引用简化
        // Map<Integer, List<Integer>> collect = stream.collect(groupingBy(h -> h.name().length(), mapping(Hero::strength, toList())));
        // collect.forEach((k, v) -> System.out.println(k + ":" + v));

        /*
         2. filtering(x->boolean, dc)  需求:根据名字长度分组,分组后组内过滤掉武力小于 90 的
         在分组收集的过程中,执行过滤先过滤,再来分组收集
         */
        // 在分组的过程中过滤 (不推荐,可以先过滤在分组,在逻辑上更加的清晰)
        // Map<Integer, List<Hero>> collect = stream.collect(groupingBy(h -> h.name().length(), filtering(h -> h.strength() >= 90, toList())));
        // collect.forEach((k, v) -> System.out.println(k + ":" + v));
        // 先过滤再分组
        // stream.filter(h -> h.strength() >= 90).collect(groupingBy(h -> h.name().length(), toList())).forEach((k, v) -> System.out.println(k + ":" + v));

        /*
         3. flatMapping(x->substream, dc)     需求:根据名字长度分组,分组后组内保留人名,并且人名切分成单个字符
         */
        // 怎么把字符串拆分成单个字段
        // 调用chars方法会返回一个IntStream整数流,其中每一个整数分别表示字符串中的每一个字符,最后使用mapToObj方法将整数转换为字符串即可
        // "令狐冲".chars().mapToObj(x -> Character.toString(x)).forEach(System.out::println);
        // 使用方法引用简化
        // "令狐冲".chars().mapToObj(Character::toString).forEach(System.out::println);
        // Map<Integer, List<String>> collect = stream.collect(groupingBy(h -> h.name().length(), flatMapping(h -> h.name().chars().mapToObj(Character::toString), toList())));
        // collect.forEach((k, v) -> System.out.println(k + ":" + v));

        /*
         4. counting() 需求:根据名字长度分组,分组后求每组个数
         */
        // Map<Integer, Long> collect = stream.collect(groupingBy(h -> h.name().length(), counting()));
        // collect.forEach((k, v) -> System.out.println(k + ":" + v));

        /*
          5. minBy((a,b)->int) 需求:根据名字长度分组,分组后求每组武功最低的人
          6. maxBy((a,b)->int) 需求:根据名字长度分组,分组后求每组武功最高的人
         */
        // Map<Integer, Optional<Hero>> collect = stream.collect(groupingBy(h -> h.name().length(), minBy((h1, h2) -> h1.strength() - h2.strength())));
        // 使用方法引用简化
        // Map<Integer, Optional<Hero>> collect = stream.collect(groupingBy(h -> h.name().length(), minBy(Comparator.comparingInt(Hero::strength)))); // 最小
        // Map<Integer, Optional<Hero>> collect = stream.collect(groupingBy(h -> h.name().length(), maxBy(Comparator.comparingInt(Hero::strength)))); // 最大
        // collect.forEach((k, v) -> System.out.println(k + ":" + v));

        /*
          7. summingInt(x->int)            需求:根据名字长度分组,分组后求每组武力和
          8. averagingDouble(x->double)    需求:根据名字长度分组,分组后求每组武力平均值
         */
        // stream.collect(groupingBy(h -> h.name().length(), summingInt(Hero::strength))).forEach((k, v) -> System.out.println(k + ":" + v));
        // stream.collect(groupingBy(h -> h.name().length(), averagingDouble(Hero::strength))).forEach((k, v) -> System.out.println(k + ":" + v));

        /*
         9. reducing(init,(p,x)->r)
         求和
         求个数
        */
        // 使用 reducing 求和
        // 思路: 先对流中的数据进行分组,分组后同过下游收集器mapping对分钟后的数据再次进行转换,对转换后的数据通过reducing进行求和
        // stream.collect(groupingBy(h -> h.name().length(), mapping(h -> h.strength(), reducing(0, (p, x) -> p + x)))).forEach((k, v) -> System.out.println(k + ":" + v));
        // 使用方法引用简化
        stream.collect(groupingBy(h -> h.name().length(), mapping(Hero::strength, reducing(0, Integer::sum)))).forEach((k, v) -> System.out.println(k + ":" + v));
    }
}
